use crate::sm3::error::Error;


pub struct PaddedStringBuffer<'a>{
    source_buffer:&'a [u8],
    pad_vec:Vec<u8>,
    frame_offset:usize
}




impl<'a> PaddedStringBuffer<'a>{

    #[allow(dead_code)]
    fn test_new(src_buffer:&'a [u8])->Self{
        Self{
            source_buffer:src_buffer,
            pad_vec: Vec::with_capacity(64),
            frame_offset:0
        }
    }


    pub fn new(src_buffer:&'a [u8])->Self{


        let mut pb = Self{
            source_buffer:src_buffer,
            pad_vec: Vec::with_capacity(64),
            frame_offset:0
        };

        //1.calculate k
        //2.padding segment
        //3.padding tail
        let k = pb.calculate_pad_length_in_bits(src_buffer.len()*8);
        pb.padding_segment(k).unwrap();
        pb.padding_tail(src_buffer.len()).unwrap();

        #[cfg(feature="print_padded_string_buffer")]
        println!("[PaddedStringBuffer]:src_buffer:{:x?}",src_buffer);
 
        #[cfg(feature="print_padded_string_buffer")]
        println!("[PaddedStringBuffer]:pad_vec:{:x?}",pb.pad_vec);       


        return pb;
    }

    pub fn iter_one_frame_copy(&mut self)->Option<[u8;64]>{
        if self.frame_offset >= self.source_buffer.len()+self.pad_vec.len(){
            return None;
        }


        let mut frame:[u8;64] = [0;64];
        for i in 0..64{
           if i+self.frame_offset< self.source_buffer.len(){
                frame[i] = self.source_buffer[self.frame_offset+i];
            } else {
                frame[i] = self.pad_vec[i+self.frame_offset-self.source_buffer.len()];
            }
        }
        self.frame_offset += 64;
        


        Some(frame)
    }






 
    fn calculate_pad_length_in_bits(&self,bit_len:usize)->usize{

        let m = bit_len % 512;
        let length = match m {
            447.. => 512+448-(m+1),
            _ => 448 - (m+1),
        };
        #[cfg(feature="print_padded_string_buffer")]
        println!("[PaddedStringBuffer]:Padding length in bits:{}",length);
 


        length
    }




    fn padding_segment(&mut self,k_in_bits:usize)->Result<(),Error>{


        self.pad_vec.push(128u8);//一般情况下，数据都是整BYTE，因此消息尾必定是128，k必定大于3？？
        for _ in 0..((k_in_bits-7)/8) {
            self.pad_vec.push(0u8);
        }
        #[cfg(feature="print_padded_string_buffer")]
        println!("[PaddedStringBuffer]:Buffer length after padding segment:{} bytes",self.pad_vec.len());



        Ok(())
    }
    
    
    fn padding_tail(&mut self,buffer_len:usize)-> Result<(),Error> {


        let bit_len = buffer_len * 8;
        for _i in 0..8{
            self.pad_vec.push((bit_len >> 8*(7-_i)) as u8);
        }
        #[cfg(feature="print_padded_string_buffer")]
        println!("[PaddedStringBuffer]:Buffer length after padding tail:{} bytes",self.pad_vec.len());




        Ok(())
    }
  


}









#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    fn test_calculate_pad_length_in_bits() {
        let nouse:[u8;10] = [0;10];
        let padder = PaddedStringBuffer::test_new(&nouse);
        let test = 800;
        let expect = 159;
        assert_eq!(expect,padder.calculate_pad_length_in_bits(test));

        let test = 120;
        let expect = 327;
        assert_eq!(expect,padder.calculate_pad_length_in_bits(test));

        let test = 1000;
        let expect = 471;
        assert_eq!(expect,padder.calculate_pad_length_in_bits(test));

    }

    #[test]
    fn test_padding_segment() {
        let nouse:[u8;10] = [0;10];
        let mut padder = PaddedStringBuffer::test_new(&nouse);
        let rtn = padder.padding_segment(31);
        assert_eq!(true,rtn.is_ok());
        assert_eq!(vec![
                    0x80u8,0x00u8,0x00u8,0x00u8
                    ],padder.pad_vec);
    }


    #[test]
    fn test_padding_tail() {
        let nouse:[u8;10] = [0;10];
        let mut padder = PaddedStringBuffer::test_new(&nouse);
        let rtn = padder.padding_tail(20);
        assert_eq!(true,rtn.is_ok());
        assert_eq!(vec![
                    0x00u8,0x00u8,0x00u8,0x00u8,0x00u8,
                    0x00u8,0x00u8,160u8
                   ],padder.pad_vec);
    }

    #[test]
    fn setup_padding_vec() {
        let sample = [0x61,0x62,0x63,0x64,0x65,0x66];
        let pad_buffer = PaddedStringBuffer::new(&sample);
        assert_eq!(&[
                    0x61u8,0x62u8,0x63u8,0x64u8,0x65u8,0x66u8
                   ],&pad_buffer.source_buffer);
    }


    #[test]
    fn test_binary_padding(){

        //61626380 00000000 00000000 00000000 00000000 00000000 00000000 00000000
        //00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000018
        let mut padder = PaddedStringBuffer::new(&[0x61u8,0x62u8,0x63u8]);
        let frame = padder.iter_one_frame_copy();
        assert_eq!(true,frame.is_some());
        assert_eq!(&[
                        0x61u8,0x62u8,0x63u8,0x80u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x00u8,
                        0x00u8,0x00u8,0x00u8,0x18u8
                        ],&frame.unwrap());
    }




}

